// FriendsService.cs
// Facebook/Framework/Service
// Copyright (c) 2007, Nikhil Kothari. All Rights Reserved.
//

using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Text;
using Facebook.Service.Core;

namespace Facebook.Service {

    /// <summary>
    /// Represents the service APIs related to the user's friends on Facebook.
    /// </summary>
    public sealed class FriendsService {

        private FacebookSession _session;

        internal FriendsService(FacebookSession session) {
            Debug.Assert(session != null);
            _session = session;
        }

        /// <summary>
        /// Checks if the specified users are friends. This corresponds to the
        /// friends.areFriends Facebook method.
        /// </summary>
        /// <param name="userID1">The first user ID.</param>
        /// <param name="userID2">The second user ID.</param>
        /// <returns>true if the users are friends; false otherwise.</returns>
        public bool AreFriends(string userID1, string userID2) {
            FacebookRequest request = new FacebookRequest(_session);
            request.Parameters["uids1"] = userID1;
            request.Parameters["uids2"] = userID2;

            FacebookResponse response = request.InvokeMethod("friends.areFriends");
            if (response.Status == FacebookResponseStatus.Succeeded) {
                Debug.Assert(response.Result is ArrayList);
                Debug.Assert(((ArrayList)response.Result).Count == 1);
                Debug.Assert(((ArrayList)response.Result)[0] is Hashtable);

                Hashtable friendInfo = (Hashtable)((ArrayList)response.Result)[0];
                object friends = friendInfo["are_friends"];

                if (friends is bool) {
                    return (bool)friends;
                }
            }

            return false;
        }

        /// <summary>
        /// Gets the list of friends of the current user. This corresponds to the
        /// friends.get and friends.getAppUsers methods.
        /// </summary>
        /// <param name="filter">The filter to apply to the list of friends.</param>
        /// <returns>A list of user IDs corresponding to the user's friends.</returns>
        public ICollection<string> GetFriends(FriendFilter filter) {
            if ( ((int)filter < 0) ||
                 ((int)filter > 4) ) {
                throw new ArgumentOutOfRangeException("filter");
            }

            if ((_session.FriendIDs != null) && (filter == FriendFilter.AllFriends)) {
                return _session.FriendIDs;
            }

            string query;
            string fieldName = "uid";

			switch (filter)
			{
				case FriendFilter.AppUsers:
					query = "SELECT uid FROM user WHERE uid IN (SELECT uid2 FROM friend WHERE uid1={0}) AND is_app_user ";
					break;
				case FriendFilter.NonAppUsers:
					query = "SELECT uid FROM user WHERE uid IN (SELECT uid2 FROM friend WHERE uid1={0}) AND NOT is_app_user ";
					break;
				case FriendFilter.AppAddedUsers:
					query = "SELECT uid FROM user WHERE uid IN (SELECT uid2 FROM friend WHERE uid1={0}) AND has_added_app";
					break;
				case FriendFilter.NonAppAddedUsers:
					query = "SELECT uid FROM user WHERE uid IN (SELECT uid2 FROM friend WHERE uid1={0}) AND NOT has_added_app";
					break;
				default:
					Debug.Assert(filter == FriendFilter.AllFriends);
					query = "SELECT uid2 FROM friend WHERE uid1={0}";
					fieldName = "uid2";
					break;
			}

            FacebookRequest request = new FacebookRequest(_session);
            request.Parameters["query"] = String.Format(query, _session.UserID);

            FacebookResponse response = request.InvokeMethod("fql.query");
            if (response.Status == FacebookResponseStatus.Succeeded) {
                if (response.Result is ArrayList) {
                    // Sometimes Facebook returns an ArrayList, and sometimes
                    // a Dictionary (eg. when there are no users).
                    // Also sometimes the IDs are returned as strings (AllFriends)
                    // and sometimes as numbers.

                    ArrayList idListInfo = (ArrayList)response.Result;

                    List<string> ids = new List<string>(idListInfo.Count);
                    foreach (Hashtable idInfo in idListInfo) {
                        ids.Add(idInfo[fieldName].ToString());
                    }
                    return ids;
                }
            }

            return new string[0];
        }
    }
}
